《数据结构与算法分析》课程设计

您所在的位置:网站首页 游戏程序开发流程 程序结构设计 《数据结构与算法分析》课程设计

《数据结构与算法分析》课程设计

2024-06-28 08:41:31| 来源: 网络整理| 查看: 265

中国矿业大学信控学院

补一下我之前在博客园发布的内容

 懒得调了,想复制完整代码直接复制最下面的,想复制分布代码去看我博客园链接吧

《数据结构与算法分析》课程设计——贪吃蛇问题 - 刷子zz - 博客园

一、问题描述#

以数据结构思想设计实现贪吃蛇小游戏。

二、需求分析#

首先需要考虑如何设计一个win运行窗口来实时显示结果

然后考虑到蛇的身子是一节一节的,此时最容易联想到的数据结构就是顺序表,链表,如果把蛇比做顺序表或者链表,在之后吃到食物的时候,身子肯定会变长,这就涉及到插入的操作,所以为了更高的效率,我们用链表实现我们的蛇的部分,最初我们把蛇身子按照四个结点打印在屏幕。

对于蛇的移动,在屏幕上面蛇的移动看起来是整个身子向前方平移一个单位,但是其原理是我们在屏幕的另一个地方把蛇从新打印一遍,又把之前的蛇身子去除掉。

对于食物的产生,随机的在地图中产生一个节点,在蛇的头坐标和食物的坐标重复的时候,食物消失,蛇的身子加长,也就是蛇的节点数增加一个。

蛇在其中的几种状态,正常状态:蛇头节点的坐标没有和墙的坐标以及自己身子的坐标重合,

被自己杀死:蛇头的坐标和蛇身子的坐标重合,

撞墙:蛇头的坐标和墙的坐标重合。

三、算法设计#

1.相关变量。#

1 1.相关变量。 2 int JudgeSum = 0; //判断是否加快 3 int Pause = 200000000; //暂停速度(移动速度) 4 int * PJ = &JudgeDirection; //用指针传值判断移动方向 5 nakebody *end = NULL; //尾节点

2.创建链表 #

贪吃蛇的身体如何保存是游戏的核心,所以我们需要用到链表来保存蛇的身体,这样就可以随时知道蛇身数据。

1 typedef struct Snakebody 2 { 3 int x, y; //蛇身的坐标 4 struct Snakebody *next;//保存下一个蛇身的地址 5 }Snakebody; //通过typedef将 Snakebody 替代 struct Snakebody

3.记录食物出现的坐标。#

1 typedef struct Snakexy 2 { 3 int x; 4 int y; 5 }Snakexy; //记录食物坐标

4.绘制初始界面和游戏地图。#

复制代码

1 #include 2 #define HEIGHT 20 //设置地图高度 3 #define WIDTH 40 //设置地图宽度 4 #define PRINTF printf("■"); 5 #define LINE printf("\n"); 6 #define EMPTY printf(" "); //因为这三个语句经常用,所以我就定义成了宏 7 void Front(); //绘制初始界面 8 void DeawMap(); //绘制地图 9 10 void Front() 11 { 12 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE);//设置红色和蓝色相加 13 MoveCursor(18, 15); 14 printf("请等待......"); 15 for (int i = 0; i x = 5 - i; 11 Pbady->y = 5; 12 if (Phead == NULL) 13 { 14 Phead = Pbady; 15 } 16 else 17 { 18 end->next = Pbady; 19 } 20 Pbady->next = NULL; 21 end = Pbady; 22 } 23 Phead_1 = Phead; 24 while (Phead_1->next != NULL)//打印蛇身 25 { 26 MoveCursor(Phead_1->x, Phead_1->y); 27 PRINTF 28 Phead_1 = Phead_1->next; 29 } 30 }

复制代码

6.产生食物,随机产生食物,如果和蛇身体重合则再次随机产生食物。#

复制代码

1 #include 2 int sum = 0; //计算得分 3 Snakexy * Food = NULL; //保存食物位置 4 void FoodRand(); //生成食物 5 void FoodRand() 6 { 7 srand((int)time(0)); 8 int x = rand() % 27 + 2;//生成随机数 9 int y = rand() % 17 + 2; 10 Phead_1 = Phead; 11 for (int i = 0; i x == x && Phead_1->y == y) 14 { 15 x = rand() % 27 + 2; 16 y = rand() % 17 + 2; 17 } 18 else 19 { 20 Phead_1 = Phead_1->next; 21 } 22 if (Phead_1->next == NULL) 23 { 24 break; 25 } 26 } 27 MoveCursor(x, y); 28 PRINTF 29 Food = (Snakexy*)malloc(sizeof(Snakexy)); 30 Food->x = x; 31 Food->y = y; 32 MoveCursor(33, 5); 33 printf(" "); 34 Showf(); 35 sum++; 36 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY);// 蓝 37 }

复制代码

rand函数功能为获取一个伪随机数,如要产生[m,n]范围内的随机数num,可用int num=rand()%(n-m+1)+m;

7.游戏刷新和暂停 ,按回车可暂停游戏。#

复制代码

1 int JudgeDirection = 4; //判断方向 2 void ControlMove(); //控制移动和暂停 3 void ControlMove() 4 { 5 if (GetAsyncKeyState(VK_UP) && 0x8000) 6 { 7 if (JudgeDirection == 2) 8 { 9 } 10 else 11 { 12 JudgeDirection = 1; 13 } 14 } 15 if (GetAsyncKeyState(VK_DOWN) && 0x8000) 16 { 17 if (JudgeDirection == 1) 18 { 19 } 20 else 21 { 22 JudgeDirection = 2; 23 } 24 } 25 if (GetAsyncKeyState(VK_RIGHT) && 0x8000) 26 { 27 if (JudgeDirection == 3) 28 { 29 } 30 else 31 { 32 JudgeDirection = 4; 33 } 34 } 35 if (GetAsyncKeyState(VK_LEFT) && 0x8000) 36 { 37 if (JudgeDirection == 4) 38 { 39 } 40 else 41 { 42 JudgeDirection = 3; 43 } 44 } 45 if (GetAsyncKeyState(VK_RETURN) && 0x0D)//判断回车 46 { 47 while (1) 48 { 49 if (GetAsyncKeyState(VK_RETURN) && 0x0D)//再次回车退出死循环 50 { 51 break; 52 } 53 } 54 } 55 }

复制代码

GetAsyncKeyState()确定用户当前是否按下了键盘上的一个键

8.显示分数和难度,更新分数和难度。#

复制代码

1 int sum = 0; //计算得分 2 int Hard = 0; //计算难度 3 void Showf(); //显分数以及难度 4 void Showf() 5 { 6 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_BLUE);// 蓝 7 MoveCursor(33, 5); 8 printf("得分:%d", sum); 9 MoveCursor(33, 6); 10 printf("难度:%d", Hard); 11 }

复制代码

9.移动光标 ,游戏不闪的原因就是我们只绘制一次地图 然后用光标定点刷新目标点。#

复制代码

1 void MoveCursor(int x, int y); //移动光标 2 void MoveCursor(int x, int y)//设置光标位置(就是输出显示的开始位置) 3 { 4 COORD pos = { x * 2,y }; 5 HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);//获得标准输出的句柄 6 SetConsoleCursorPosition(output, pos); //设置光标位置 7 }

复制代码

COORD是Windows API中定义的一种结构体

 

10.检测,检测是否吃到食物,是否撞墙,是否撞到自己。#

复制代码

1 void Jfood(); //检测是否吃到食物 2 void Jwall(); //检测蛇头是否撞墙 3 void Jsnake(); //检测蛇头是否撞到蛇身 4 void Jfood() 5 { 6 Phead_1 = Phead; 7 if (Phead_1->x == Food->x&&Phead_1->y == Food->y) 8 { 9 FoodRand(); 10 JudgeSum += 1; 11 if (JudgeSum == 5) 12 { 13 JudgeSum = 0;//如果JudgeSum等于5则从新判断 14 Hard += 1; 15 Pause -= 20000000;//每成立一次循环减少20000000 16 } 17 while (Phead_1->next != NULL) 18 { 19 Phead_1 = Phead_1->next; 20 } 21 Snakebody *S = (Snakebody*)malloc(sizeof(Snakebody)); 22 S->x = Food->x; 23 S->y = Food->y; 24 S->next = NULL; 25 Phead_1->next = S; 26 ControlMove(); 27 MoveCursor(Phead_1->x, Phead_1->y); 28 PRINTF 29 } 30 //获取食物的坐标和蛇头做对比 31 } 32 void Jwall() 33 { 34 if (Phead->x == 0 || Phead->x == 29 || Phead->y == 0 || Phead->y == 19) 35 { 36 MoveCursor(10, 20); 37 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);//设置红色 38 printf("抱歉,你撞到了自己,游戏结束! "); 39 system("pause>nul"); 40 exit(0); 41 } 42 } 43 void Jsnake() 44 { 45 Phead_1 = Phead->next; 46 while (Phead_1->next != NULL) 47 { 48 if ((Phead->x == Phead_1->x) && (Phead->y == Phead_1->y)) 49 { 50 MoveCursor(10, 20); 51 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);//设置红色 52 printf("抱歉,你撞到了自己,游戏结束! "); 53 system("pause>nul"); 54 exit(0); 55 } 56 Phead_1 = Phead_1->next; 57 } 58 }

复制代码

11.游戏循环#

复制代码

1 void Move(); //游戏运行 2 void Move() 3 { 4 while (1) 5 { 6 Phead_1 = Phead; 7 while (Phead_1->next->next != NULL) 8 { 9 Phead_1 = Phead_1->next; 10 } 11 Phead_1->next = NULL; 12 for (int i = 0; i < Pause; i++) {} 13 ControlMove(); 14 MoveCursor(Phead_1->x, Phead_1->y); 15 EMPTY 16 //上面为消除尾部 17 Snakebody *Phead_2 = (Snakebody*)malloc(sizeof(Snakebody)); 18 if (*PJ == 1) 19 { 20 Phead_2->x = Phead->x; 21 Phead_2->y = Phead->y - 1; 22 } 23 if (*PJ == 2) 24 { 25 Phead_2->x = Phead->x; 26 Phead_2->y = Phead->y + 1; 27 } 28 if (*PJ == 3) 29 { 30 Phead_2->x = Phead->x - 1; 31 Phead_2->y = Phead->y; 32 } 33 if (*PJ == 4) 34 { 35 Phead_2->x = Phead->x + 1; 36 Phead_2->y = Phead->y; 37 } 38 Phead_2->next = Phead; 39 Phead = Phead_2; 40 MoveCursor(Phead_2->x, Phead_2->y); 41 PRINTF 42 Jfood(); 43 Jwall(); 44 Jsnake(); 45 MoveCursor(40, 20); 46 } 47 }

复制代码

12.释放内存#

复制代码

1 void Free(); //释放内存 2 void Free() 3 { 4 while (Phead->next != NULL) 5 { 6 Phead = Phead->next; 7 free(Phead); 8 } 9 free(Phead); 10 }

复制代码

附录:完整代码# #include #include #include #define HEIGHT 20 //设置地图高度 #define WIDTH 40 //设置地图宽度 #define PRINTF printf("■"); #define LINE printf("\n"); #define EMPTY printf(" "); typedef struct Snakebody { int x, y;//身体的坐标 struct Snakebody *next;//结构指针 }Snakebody;//先来创建保持身体的链表,贪吃蛇的核心代码就是该如何保存蛇的身体 typedef struct Snakexy { int x; int y; }Snakexy; //记录食物坐标 int sum = 0; //计算得分 int JudgeSum = 0; //判断是否加快 int Hard = 0; //计算难度 int Pause = 200000000; //暂停速度(移动速度) int JudgeDirection = 4; //判断方向 int * PJ = &JudgeDirection; //用指针传值判断移动方向 Snakebody *Phead = NULL; //存储着整个蛇身 不可更改 Snakebody *Phead_1 = NULL; //指向蛇身 Snakebody *Pbady = NULL; //创建节点 Snakebody *end = NULL; //尾节点 Snakexy * Food = NULL; //保存食物位置 void Front(); //游戏开始页面1 void Jfood(); //检测是否吃到食物1 void Jwall(); //检测蛇头是否撞墙1 void Jsnake(); //检测蛇头是否撞到蛇身1 void ISnake(); //初始化蛇身1 void DeawMap(); //绘制地图1 void FoodRand(); //生成食物1 void ControlMove(); //控制移动和暂停1 void MoveCursor(int x, int y); //移动光标1 void Move(); //游戏运行1 void Showf(); //显分数以及难度1 void Free(); //释放内存 int main() { Front(); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN);//绿 DeawMap(); Showf(); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY);// 暗白 MoveCursor(34, 10); printf("↑"); MoveCursor(31, 11); printf("使用←↓→来控制"); MoveCursor(31, 12); printf("蛇的移动,撞墙游"); MoveCursor(31, 13); printf("戏结束,每5分增 "); MoveCursor(31, 14); printf("一个难度(速度)"); ISnake(); FoodRand(); MoveCursor(40, 20); Move(); return 0; } void Front() { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE);//设置红色和蓝色相加 MoveCursor(18, 15); printf("请等待......"); for (int i = 0; i y == y) { x = rand() % 27 + 2; y = rand() % 17 + 2; } else { Phead_1 = Phead_1->next; } if (Phead_1->next == NULL) { break; } } MoveCursor(x, y); PRINTF Food = (Snakexy*)malloc(sizeof(Snakexy)); Food->x = x; Food->y = y; MoveCursor(33, 5); printf(" "); Showf(); sum++; SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY);// 蓝 } void ControlMove() { if (GetAsyncKeyState(VK_UP) && 0x8000) { if (JudgeDirection == 2) { } else { JudgeDirection = 1; } } if (GetAsyncKeyState(VK_DOWN) && 0x8000) { if (JudgeDirection == 1) { } else { JudgeDirection = 2; } } if (GetAsyncKeyState(VK_RIGHT) && 0x8000) { if (JudgeDirection == 3) { } else { JudgeDirection = 4; } } if (GetAsyncKeyState(VK_LEFT) && 0x8000) { if (JudgeDirection == 4) { } else { JudgeDirection = 3; } } if (GetAsyncKeyState(VK_RETURN) && 0x0D) { while (1) { if (GetAsyncKeyState(VK_RETURN) && 0x0D) { break; } } } } void ISnake() { for (int i = 0; i < 5; i++) { Pbady = (Snakebody*)malloc(sizeof(Snakebody)); Pbady->x = 5 - i; Pbady->y = 5; if (Phead == NULL) { Phead = Pbady; } else { end->next = Pbady; } Pbady->next = NULL; end = Pbady; } Phead_1 = Phead; while (Phead_1->next != NULL) { MoveCursor(Phead_1->x, Phead_1->y); PRINTF Phead_1 = Phead_1->next; } } void Move() { while (1) { Phead_1 = Phead; while (Phead_1->next->next != NULL) { Phead_1 = Phead_1->next; } Phead_1->next = NULL; for (int i = 0; i < Pause; i++) {} ControlMove(); MoveCursor(Phead_1->x, Phead_1->y); EMPTY //上面为消除尾部 Snakebody *Phead_2 = (Snakebody*)malloc(sizeof(Snakebody)); if (*PJ == 1) { Phead_2->x = Phead->x; Phead_2->y = Phead->y - 1; } if (*PJ == 2) { Phead_2->x = Phead->x; Phead_2->y = Phead->y + 1; } if (*PJ == 3) { Phead_2->x = Phead->x - 1; Phead_2->y = Phead->y; } if (*PJ == 4) { Phead_2->x = Phead->x + 1; Phead_2->y = Phead->y; } Phead_2->next = Phead; Phead = Phead_2; MoveCursor(Phead_2->x, Phead_2->y); PRINTF Jfood(); Jwall(); Jsnake(); MoveCursor(40, 20); } } void Jfood() { Phead_1 = Phead; if (Phead_1->x == Food->x&&Phead_1->y == Food->y) { FoodRand(); JudgeSum += 1; if (JudgeSum == 5) { JudgeSum = 0; Hard += 1; Pause -= 20000000; } while (Phead_1->next != NULL) { Phead_1 = Phead_1->next; } Snakebody *S = (Snakebody*)malloc(sizeof(Snakebody)); S->x = Food->x; S->y = Food->y; S->next = NULL; Phead_1->next = S; ControlMove(); MoveCursor(Phead_1->x, Phead_1->y); PRINTF } //获取食物的坐标和蛇头做对比 } void Jwall() { if (Phead->x == 0 || Phead->x == 29 || Phead->y == 0 || Phead->y == 19) { MoveCursor(10, 20); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);//设置红色 printf("抱歉,你撞到了自己,游戏结束! "); system("pause>nul"); exit(0); } } void Jsnake() { Phead_1 = Phead->next; while (Phead_1->next != NULL) { if ((Phead->x == Phead_1->x) && (Phead->y == Phead_1->y)) { MoveCursor(10, 20); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);//设置红色 printf("抱歉,你撞到了自己,游戏结束! "); system("pause>nul"); exit(0); } Phead_1 = Phead_1->next; } } void Showf() { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_BLUE);// 蓝 MoveCursor(33, 5); printf("得分:%d", sum); MoveCursor(33, 6); printf("难度:%d", Hard); } void Free() { while (Phead->next != NULL) { Phead = Phead->next; free(Phead); } free(Phead); }



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭